//
// (C) Copyright 2009 Irantha Suwandarathna (irantha@gmail.com)
// All rights reserved.
//

/* Copyright (c) 1995-2000, The Hypersonic SQL Group.
 * All rights reserved.
 *
 * Redistribution and use _in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions _in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer _in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the Hypersonic SQL Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software consists of voluntary contributions made by many individuals
 * on behalf of the Hypersonic SQL Group.
 *
 *
 * For work added by the HSQL Development Group:
 *
 * Copyright (c) 2001-2008, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use _in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions _in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer _in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


using System;
using System.Text;
using System.Collections.Generic;


namespace EffiProzDB
{

    // fredt@users 20021103 - patch 1.7.2 - fix bug _in revokeAll()
    // fredt@users 20021103 - patch 1.7.2 - allow for drop table, etc.
    // when tables are dropped or renamed, changes are reflected _in the
    // permissions held _in User objects.
    // boucherb@users 200208-200212 - doc 1.7.2 - update
    // boucherb@users 200208-200212 - patch 1.7.2 - metadata
    // unsaved@users - patch 1.8.0 moved right managament to new classes

    /**
     * A User Object holds the name, password for a
     * particular database user.<p>
     *
     * Enhanced _in successive versions of HSQLDB.
     *
     * @author Thomas Mueller (Hypersonic SQL Group)
     * @version 1.8.0
     * @since Hypersonic SQL
     */
    public class User
    {

        /** true if this user is the sys user. */
        private bool _isSys;

        /** true if this user is the public user. */
        private bool _isPublic;

        /** user name. */
        private string sName;

        /** password. */
        private string sPassword;

        /** default schema when new Sessions started (defaults to PUBLIC schema) */
        private HsqlNameManager.HsqlName initialSchema = null;

        /** grantee object. */
        private Grantee grantee;

        /**
         * Constructor
         */
        public User(string name, string password,
                Grantee inGrantee)
        {

            sName = name;
            grantee = inGrantee;

            bool granteeOk = grantee != null
                                || GranteeManager.isReserved(name);

            if (!granteeOk)
            {
                Trace.doAssert(false,
                               Trace.getMessage(Trace.MISSING_GRANTEE) + ": "
                               + name);
            }

            setPassword(password);

            _isSys = name.Equals(GranteeManager.SYSTEM_AUTHORIZATION_NAME);
            _isPublic = name.Equals(GranteeManager.PUBLIC_ROLE_NAME);
        }

        public string getName()
        {
            return sName;
        }

        public void setPassword(string password)
        {

            // TODO:
            // checkComplexity(password);
            // requires: UserManager.createSAUser(), UserManager.createPublicUser()
            sPassword = password;
        }

        /**
         * Checks if this object's password attibute equals
         * specified argument, else throws.
         */
        public void checkPassword(string test)
        {
            Trace.check(test.Equals(sPassword), Trace.ACCESS_IS_DENIED);
        }

        /**
         * Returns true if this User object is for a user with the
         * database administrator role.
         */
        public bool isSys()
        {
            return _isSys;
        }

        /**
         * Returns the initial schema for the user
         */
        public HsqlNameManager.HsqlName getInitialSchema()
        {
            return initialSchema;
        }

        /**
         * This class does not have access to the SchemaManager, therefore
         * caller should verify that the given schemaName exists.
         *
         * @param schemaName Name of an existing schema.  Null value allowed,
         *                   which means use the DB default session schema.
         */
        public void setInitialSchema(HsqlNameManager.HsqlName schema)
        {
            initialSchema = schema;
        }

        /**
         * Returns true if this User object represents the PUBLIC user
         */
        public bool isPublic()
        {
            return _isPublic;
        }

        /**
         * Returns the ALTER USER DDL character sequence that preserves the
         * this user's current password value and mode. <p>
         *
         * @return  the DDL
         */
        public string getAlterUserDDL()
        {

            StringBuilder sb = new StringBuilder();

            sb.Append(Token.T_ALTER).Append(' ');
            sb.Append(Token.T_USER).Append(' ');
            sb.Append(sName).Append(' ');
            sb.Append(Token.T_SET).Append(' ');
            sb.Append(Token.T_PASSWORD).Append(' ');
            sb.Append('"').Append(sPassword).Append('"');

            return sb.ToString();
        }

        /**
         * returns the DDL string
         * sequence that creates this user.
         *
         */
        public string getCreateUserDDL()
        {

            StringBuilder sb = new StringBuilder(64);

            sb.Append(Token.T_CREATE).Append(' ');
            sb.Append(Token.T_USER).Append(' ');
            sb.Append(sName).Append(' ');
            sb.Append(Token.T_PASSWORD).Append(' ');
            sb.Append('"').Append(sPassword).Append('"');

            return sb.ToString();
        }

        /**
         * Retrieves the redo log character sequence for connecting
         * this user
         *
         * @return the redo log character sequence for connecting
         *      this user
         */
        public string getConnectStatement()
        {

            StringBuilder sb = new StringBuilder();

            sb.Append(Token.T_CONNECT).Append(' ');
            sb.Append(Token.T_USER).Append(' ');
            sb.Append(sName);

            return sb.ToString();
        }

        /**
         * Retrieves the Grantee object for this User.
         */
        public Grantee getGrantee()
        {
            return grantee;
        }

        /**
         * Sets the Grantee object for this User.
         * This is done _in the constructor for all users except the special
         * users SYSTEM and PUBLIC, which have to be set up before the
         * Managers are initialized.
         */
        public void setGrantee(Grantee inGrantee)
        {

            if (grantee != null)
            {
                Trace.doAssert(false,
                               Trace.getMessage(Trace.CHANGE_GRANTEE) + ": "
                               + sName);
            }

            grantee = inGrantee;
        }

        // Legacy wrappers

        /**
         * Returns true if this User object is for a user with the
         * database administrator role.
         */
        public bool isAdmin()
        {
            return grantee.isAdmin();
        }

        /**
         * Retrieves a string[] whose elements are the names, of the rights
         * explicitly granted with the GRANT command to this <code>User</code>
         * object on the <code>Table</code> object identified by the
         * <code>name</code> argument.
         * * @return array of Strings naming the rights granted to this
         *        <code>User</code> object on the <code>Table</code> object
         *        identified by the <code>name</code> argument.
         * @param name a <code>Table</code> object identifier
         *
         */
        public String[] listGrantedTablePrivileges(HsqlNameManager.HsqlName name)
        {
            return grantee.listGrantedTablePrivileges(name);
        }

        /**
         * Retrieves the distinct set of Java <code>Class</code> FQNs
         * for which this <code>User</code> object has been
         * granted <code>ALL</code> (the Class execution privilege). <p>
         * @param andToPublic if <code>true</code>, then the set includes the
         *        names of classes accessible to this <code>User</code> object
         *        through grants to its <code>PUBLIC</code> <code>User</code>
         *        object attribute, else only direct grants are inlcuded.
         * @return the distinct set of Java Class FQNs for which this
         *        this <code>User</code> object has been granted
         *        <code>ALL</code>.
         *
         */
        public HashSet<string> getGrantedClassNames(bool andToPublic)
        {
            return grantee.getGrantedClassNames(andToPublic);
        }

        /**
         * Retrieves the map object that represents the rights that have been
         * granted on database objects.  <p>
         *
         * The map has keys and values with the following interpretation: <P>
         *
         * <UL>
         * <LI> The keys are generally (but not limited to) objects having
         *      an attribute or value equal to the name of an actual database
         *      object.
         *
         * <LI> Specifically, the keys act as database object identifiers.
         *
         * <LI> The values are always int objects, each formed by combining
         *      a set of flags, one for each of the access rights defined in
         *      UserManager: {SELECT, INSERT, UPDATE and DELETE}.
         * </UL>
         */
        public Dictionary<object, int> getRights()
        {
            return grantee.getRights();
        }

        /**
         * Checks that this User object is for a user with the
         * database administrator role. Otherwise it throws.
         */
        public void checkAdmin()
        {
            grantee.checkAdmin();
        }

        /**
         * Checks if any of the rights represented by the rights
         * argument have been granted on the specified database object. <p>
         *
         * This is done by checking that a mapping exists _in the rights map
         * from the dbobject argument for at least one of the rights
         * contained _in the rights argument. Otherwise, it throws.
         */
        public void check(HsqlNameManager.HsqlName dbobject, int rights)
        {
            grantee.check(dbobject, rights);
        }

        public void check(string dbobject)
        {
            grantee.check(dbobject);
        }

        /**
         * Returns true if any of the rights represented by the
         * rights argument has been granted on the database object identified
         * by the dbobject argument. <p>
         *
         * This is done by checking that a mapping exists _in the rights map
         * from the dbobject argument for at least one of the rights
         * contained _in the rights argument.
         */
        public bool isAccessible(HsqlNameManager.HsqlName dbobject, int rights)
        {
            return grantee.isAccessible(dbobject, rights);
        }

        /**
         * Returns true if any right at all has been granted to this User object
         * on the database object identified by the dbobject argument.
         */
        public bool isAccessible(string dbobject)
        {
            return grantee.isAccessible(dbobject);
        }

        public bool isAccessible(HsqlNameManager.HsqlName dbobject)
        {
            return grantee.isAccessible(dbobject);
        }
    }
}
